/* sim.c
 *
 * Micropolis, Unix Version.  This game was released for the Unix platform
 * in or about 1990 and has been modified for inclusion in the One Laptop
 * Per Child program.  Copyright (C) 1989 - 2007 Electronic Arts Inc.  If
 * you need assistance with this program, you may contact:
 *   http://wiki.laptop.org/go/Micropolis  or email  micropolis@laptop.org.
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or (at
 * your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.  You should have received a
 * copy of the GNU General Public License along with this program.  If
 * not, see <http://www.gnu.org/licenses/>.
 * 
 *             ADDITIONAL TERMS per GNU GPL Section 7
 * 
 * No trademark or publicity rights are granted.  This license does NOT
 * give you any right, title or interest in the trademark SimCity or any
 * other Electronic Arts trademark.  You may not distribute any
 * modification of this program using the trademark SimCity or claim any
 * affliation or association with Electronic Arts Inc. or its employees.
 * 
 * Any propagation or conveyance of this program must include this
 * copyright notice and these terms.
 * 
 * If you convey this program (or any modifications of it) and assume
 * contractual liability for the program to recipients of it, you agree
 * to indemnify Electronic Arts for any liability that those contractual
 * assumptions impose on Electronic Arts.
 * 
 * You may not misrepresent the origins of this program; modified
 * versions of the program must be marked as such and not identified as
 * the original program.
 * 
 * This disclaimer supplements the one included in the General Public
 * License.  TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
 * PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
 * OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK.  THE ENTIRE RISK OF
 * SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU.  ELECTRONIC ARTS
 * DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
 * INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
 * FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
 * RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
 * USAGE, OR TRADE PRACTICE.  ELECTRONIC ARTS DOES NOT WARRANT AGAINST
 * INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
 * MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
 * UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
 * WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
 * CORRECTED.  NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
 * ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY.  SOME
 * JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
 * WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
 * CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
 * NOT APPLY TO YOU.
 */
#include "sim.h"

void signal_init();
void sim_update_evaluations(void);
void sim_update_editors(void);
void sim_update_budgets(void);
void sim_update_graphs(void);
void sim_update_maps(void);

/* Sim City */

char *MicropolisVersion = "4.0";
Sim *sim = NULL;
int sim_loops = 0;
int sim_delay = 50;
int sim_skips = 0;
int sim_skip = 0;
int sim_paused = 0;
int sim_paused_speed = 3;
int sim_tty = 0;

#ifdef CAM
int sim_just_cam = 0;
#endif
int heat_steps = 0;
int heat_flow = -7;
int heat_rule = 0;
int heat_wrap = 3;
struct timeval start_time, now_time, beat_time, last_now_time;
char *CityFileName = NULL;
int Startup = 0;
char *StartupName = NULL;
int WireMode = 0;
int MultiPlayerMode = 0;
int SugarMode = 0;
int TilesAnimated = 0;
int DoAnimation = 1;
int DoMessages = 1;
int DoNotices = 1;
char *Displays = NULL;
char *FirstDisplay = NULL;
int ExitReturn = 0;

void sim_exit(int val)
{
    tkMustExit = 1;
    ExitReturn = val;
}

void sim_really_exit(int val)
{
    DoStopMicropolis();

    exit(val);
}

#define COPY(FROM, TO) \
  TO = ckalloc(strlen(FROM) + 1); \
  strcpy(TO, FROM);

#define TESTDIR(DIR, NAME) \
  if ((stat(DIR, &statbuf) == -1) || \
      !(S_ISDIR(statbuf.st_mode))) { \
    fprintf(stderr, \
	    "Can't find the directory \"%s\"!\n", DIR); \
    fprintf(stderr, \
	    "The environment variable \"%s\" should name a directory.\n", \
	    NAME); \
    lost = 1; \
  }

void env_init(void)
{
    char dir[256];
    char *s;
    struct stat statbuf;
    int lost = 0;

    if((s = getenv("SIMHOME")) == NULL)
    {
        s = ".";
    }
    COPY(s, HomeDir);
    TESTDIR(HomeDir, "$SIMHOME");

    sprintf(dir, "%s/res/", HomeDir);
    COPY(dir, ResourceDir);
    TESTDIR(ResourceDir, "$SIMHOME/res");

    {
        extern char *TCL_Library, *TK_Library;

        TCL_Library = TK_Library = ResourceDir;
    }

    if(lost)
    {
        fprintf(stderr, "Please check the environment or reinstall Micropolis and try again! Sorry!\n");
        sim_exit(1);            // Just sets tkMustExit and ExitReturn
        return;
    }

    gettimeofday(&now_time, NULL);
    last_now_time = now_time;
}

void sim_init(void)
{
    gettimeofday(&start_time, NULL);
    gettimeofday(&beat_time, NULL);

    signal_init();

    UserSoundOn = 1;
    MustUpdateOptions = 1;
    HaveLastMessage = 0;
    ScenarioID = 0;
    StartingYear = 1900;
    tileSynch = 0x01;
    sim_skips = sim_skip = 0;
    autoGo = 1;
    CityTax = 7;
    CityTime = 50;
    autoBulldoze = 1;
    autoBudget = 1;
    MesNum = 0;
    LastMesTime = 0;
    flagBlink = 1;
    SimSpeed = 3;
    ChangeEval();
    MessagePort = 0;
    MesX = 0;
    MesY = 0;
    sim_paused = 0;
    sim_loops = 0;
    InitSimLoad = 2;
    tkMustExit = 0;
    ExitReturn = 0;

    InitializeSound();
    initMapArrays();
    initGraphs();
    InitFundingLevel();
#if 0
    loadObjectData();
#endif
    setUpMapProcs();
    StopEarthquake();
    ResetMapState();
    ResetEditorState();
    ClearMap();
    InitWillStuff();
    SetFunds(5000);
    setSpeed(0);
    setSkips(0);
}

int triedToBailOnce = 0;

void SignalExitHandler()
{
    if(triedToBailOnce)
    {
        exit(-1);
    }
    else
    {
        triedToBailOnce = 1;
        fprintf(stderr, "\nMicropolis has been terminated by a signal.\n");
        fprintf(stderr, "Pick a window -- you're leaving!\n\n");
        fflush(stderr);
        sim_really_exit(-1);
    }
}

void signal_init()
{
    signal(SIGHUP, (void (*)()) SignalExitHandler);
    signal(SIGINT, (void (*)()) SignalExitHandler);
    signal(SIGQUIT, (void (*)()) SignalExitHandler);
    signal(SIGTERM, (void (*)()) SignalExitHandler);
}

void sim_update(void)
{
    gettimeofday(&now_time, NULL);

    flagBlink = (now_time.tv_usec < 500000) ? 1 : -1;

    if(SimSpeed && !heat_steps)
    {
        TilesAnimated = 0;
    }

    sim_update_editors();

    sim_update_maps();
    sim_update_graphs();
    sim_update_budgets();
    sim_update_evaluations();

    UpdateFlush();
}

void sim_update_editors(void)
{
    SimView *view;

    for(view = sim->editor; view != NULL; view = view->next)
    {
#if 1
        CancelRedrawView(view);
        view->invalid = 1;
        DoUpdateEditor(view);
#else
        EventuallyRedrawView(view);
#endif
    }

    DoUpdateHeads();
}

void sim_update_maps(void)
{
    SimView *view;
    int i;

    for(view = sim->map; view != NULL; view = view->next)
    {
        int mustUpdateMap = NewMapFlags[view->map_state] || NewMap || ShakeNow;

        if(mustUpdateMap)
        {
            view->invalid = 1;
        }
        if(view->invalid)
        {
#if 1
            if(mustUpdateMap)
            {
//fprintf(stderr, "sim_update_maps mustUpdateMap\n");
//  view->skip = 0;
            }
            if(DoUpdateMap(view))
            {
//          CancelRedrawView(view);
//    view->invalid = 1;
            }
#else
            EventuallyRedrawView(view);
#endif
        }
    }

    NewMap = 0;
    for(i = 0; i < NMAPS; i++)
    {
        NewMapFlags[i] = 0;
    }
}

void sim_update_graphs(void)
{
    graphDoer();
}

void sim_update_budgets(void)
{
    if((sim_skips != 0) && (sim_skip != 0))
    {
        return;
    }

    UpdateBudgetWindow();
}

void sim_update_evaluations(void)
{
    if((sim_skips != 0) && (sim_skip != 0))
    {
        return;
    }

    scoreDoer();
}

#ifdef CAM

sim_update_cams(void)
{
    SimCam *scam;

    if((sim_skips != 0) && (sim_skip != 0))
    {
        return;
    }

    for(scam = sim->scam; scam != NULL; scam = scam->next)
    {
        CancelRedrawView(scam);
        scam->invalid = 1;
        handle_scam(scam);
    }
}

#endif /* CAM */

short *CellSrc = NULL;
short *CellDst = NULL;

#define SRCCOL (WORLD_Y + 2)
#define DSTCOL WORLD_Y

#define CLIPPER_LOOP_BODY(CODE) \
    src = CellSrc; dst = CellDst; \
    for (x = 0; x < WORLD_X;) { \
      short nw, n, ne, w, c, e, sw, s, se; \
      \
      src = CellSrc + (x * SRCCOL); dst = CellDst + (x * DSTCOL); \
      w = src[0]; c = src[SRCCOL]; e = src[2 * SRCCOL]; \
      sw = src[1]; s = src[SRCCOL + 1]; se = src[(2 * SRCCOL) + 1]; \
      \
      for (y = 0; y < WORLD_Y; y++) { \
        nw = w; w = sw; sw = src[2]; \
	n = c; c = s; s = src[SRCCOL + 2]; \
	ne = e; e = se; se = src[(2 * SRCCOL) + 2]; \
	{ CODE } \
	src++; dst++; \
      } \
      x++; /* src += SRCCOL - 3; dst += DSTCOL - 1; */ \
      src = CellSrc + ((x + 1) * SRCCOL) - 3; dst = CellDst + ((x + 1) * DSTCOL) - 1; \
      \
      nw = src[1]; n = src[SRCCOL + 1]; ne = src[(2 * SRCCOL) + 1]; \
      w = src[2]; c = src[SRCCOL + 2]; e = src[(2 * SRCCOL) + 2]; \
      \
      for (y = WORLD_Y - 1; y >= 0; y--) { \
        sw = w; w = nw; nw = src[0]; \
        s = c; c = n; n = src[SRCCOL]; \
        se = e; e = ne; ne = src[2 * SRCCOL]; \
	{ CODE } \
	src--; dst--; \
      } \
      x++; /* src += SRCCOL + 3; dst += DSTCOL + 1; */ \
    }

void sim_heat(void)
{
    int x, y;
    static int a = 0;
    short *src, *dst;
    register int fl = heat_flow;

    if(CellSrc == NULL)
    {
        CellSrc = (short *) ckalloc((WORLD_X + 2) * (WORLD_Y + 2) * sizeof(short));
        CellDst = &Map[0][0];
    }

    src = CellSrc + SRCCOL + 1;
    dst = CellDst;

/*
 * Copy wrapping edges:
 *
 *	0	ff	f0 f1 ... fe ff		f0
 *
 *	1	0f	00 01 ... 0e 0f		00
 *	2	1f	10 11 ... 1e 1f		10
 *		..	.. ..     .. ..		..
 *		ef	e0 e1 ... ee ef		e0
 *	h	ff	f0 f1 ... fe ff		f0
 *
 *	h+1	0f	00 01 ... 0e 0f		00
 *
 * wrap value:	effect:
 *	0	no effect
 *	1	copy future=>past, no wrap
 *	2	no copy, wrap edges
 *	3	copy future=>past, wrap edges
 *	4	copy future=>past, same edges
 */

    switch (heat_wrap)
    {
        case 0:
            break;
        case 1:
            for(x = 0; x < WORLD_X; x++)
            {
                memcpy(src, dst, WORLD_Y * sizeof(short));
                src += SRCCOL;
                dst += DSTCOL;
            }
            break;
        case 2:
            for(x = 0; x < WORLD_X; x++)
            {
                src[-1] = src[WORLD_Y - 1];
                src[WORLD_Y] = src[0];
                src += SRCCOL;
                dst += DSTCOL;
            }
            memcpy(CellSrc, CellSrc + (SRCCOL * WORLD_X), SRCCOL * sizeof(short));
            memcpy(CellSrc + SRCCOL * (WORLD_X + 1), CellSrc + SRCCOL, SRCCOL * sizeof(short));
            break;
        case 3:
            for(x = 0; x < WORLD_X; x++)
            {
                memcpy(src, dst, WORLD_Y * sizeof(short));
                src[-1] = src[WORLD_Y - 1];
                src[WORLD_Y] = src[0];
                src += SRCCOL;
                dst += DSTCOL;
            }
            memcpy(CellSrc, CellSrc + (SRCCOL * WORLD_X), SRCCOL * sizeof(short));
            memcpy(CellSrc + SRCCOL * (WORLD_X + 1), CellSrc + SRCCOL, SRCCOL * sizeof(short));
            break;
        case 4:
            src[0] = dst[0];
            src[1 + WORLD_Y] = dst[WORLD_Y - 1];
            src[(1 + WORLD_X) * SRCCOL] = dst[(WORLD_X - 1) * DSTCOL];
            src[((2 + WORLD_X) * SRCCOL) - 1] = dst[(WORLD_X * WORLD_Y) - 1];
            for(x = 0; x < WORLD_X; x++)
            {
                memcpy(src, dst, WORLD_Y * sizeof(short));
                src[-1] = src[0];
                src[WORLD_Y] = src[WORLD_Y - 1];
                src += SRCCOL;
                dst += DSTCOL;
            }
            memcpy(CellSrc + (SRCCOL * (WORLD_X + 1)), CellSrc + (SRCCOL * WORLD_X), SRCCOL * sizeof(short));
            memcpy(CellSrc, CellSrc + SRCCOL, SRCCOL * sizeof(short));
            break;
    }

    switch (heat_rule)
    {

        case 0:
#define HEAT \
	a += nw + n + ne + w + e + sw + s + se + fl; \
	dst[0] = ((a >> 3) & LOMASK) | \
		     (ANIMBIT | BURNBIT | BULLBIT); \
	a &= 7;

            CLIPPER_LOOP_BODY(HEAT);
            break;

        case 1:
#define ECOMASK 0x3fc
#define ECO \
      c -= fl; n -= fl; s -= fl; e -= fl; w -= fl; \
      ne -= fl; nw -= fl; se -= fl; sw -= fl; \
      \
      /* anneal */ \
      { int sum = (c&1) + (n&1) + (s&1) + (e&1) + (w&1) + \
		  (ne&1) + (nw&1) + (se&1) + (sw&1), cell; \
	if (((sum > 5) || (sum == 4))) { \
	  /* brian's brain */ \
	  cell = ((c <<1) & (0x3fc)) | \
		 (((((c >>1)&3) == 0) && \
		   (((n&2) + (s&2) + (e&2) + (w&2) + \
		     (ne&2) + (nw&2) + (se&2) + (sw&2)) == (2 <<1)) \
		  ) ? 2 : 0) | \
		 1; \
	} else { \
	  /* anti-life */ \
	  sum = ((n&2) + (s&2) + (e&2) + (w&2) + \
		 (ne&2) + (nw&2) + (se&2) + (sw&2)) >>1; \
	  cell = (((c ^ 2) <<1) & ECOMASK) | \
		 ((c&2) ? ((sum != 5) ? 2 : 0) \
			: (((sum != 5) && (sum != 6)) ? 2 : 0)); \
	} \
	dst[0] = ((fl + cell) & LOMASK) | \
		 (ANIMBIT | BURNBIT | BULLBIT); \
      } \
      c += fl; n += fl; s += fl; e += fl; w += fl; \
      ne += fl; nw += fl; se += fl; sw += fl;

            CLIPPER_LOOP_BODY(ECO);
            break;
    }
}

void sim_timeout_loop(short doSim)
{
    if(SimSpeed)
    {
        sim_loop(doSim);
    }
    DoTimeoutListen();
}

void sim_loop(int doSim)
{
#ifdef CAM
    if(!sim_just_cam)
    {
#endif
        if(heat_steps)
        {
            int j;

            for(j = 0; j < heat_steps; j++)
            {
                sim_heat();
            }

            MoveObjects();
/*
      InvalidateMaps();
*/
            NewMap = 1;
        }
        else
        {
            if(doSim)
            {
                SimFrame();
            }
            MoveObjects();
        }

        sim_loops++;
        sim_update();
#ifdef CAM
    }
    else
    {
        sim_update_cams();
        UpdateFlush();
        DoTimeoutListen();
    }
#endif
}

int MatchArg(char *arg, char *pat)
{
    while(*pat && *arg)
    {
        if(tolower(*arg) != tolower(*pat))
        {
            if(*pat == '_')
            {
                pat++;
                continue;
            }
            return (0);
        }
        arg++;
        pat++;
    }
    return (*arg == '\0');
}

int main(int argc, char *argv[])
{
    int c, errflg = 0;
    extern int isatty();

    printf("Welcome to X11 Multi Player Micropolis version %s by Will Wright, Don Hopkins.\n", MicropolisVersion);
    printf("Copyright (C) 2002 by Electronic Arts, Maxis. All rights reserved.\n");

    while(!errflg && !tkMustExit && (c = getopt(argc, argv, "tcwmSR:gs:l:")) != -1)
    {
        switch (c)
        {

            case 't':          /* TTY mode */
                sim_tty = isatty(0);
                break;

            case 'c':          /* Create Own Colormap */
            {
                extern int TK_CreateColormap;

                TK_CreateColormap = 1;
            }
                break;

            case 'w':          /* Wire Mode (don't use shared memory) */
                WireMode = 1;
                break;

            case 'm':          /* Multi Player Mode */
                MultiPlayerMode = 1;
                break;

            case 'S':          /* Sugar Mode */
                SugarMode = 1;
                break;

            case 'R':          /* Root Window ID */
                c = atoi(optarg);
                if(c)
                {
                    tk_RootWindow = c;
                }
                else
                {
                    errflg = 1;
                }
                break;

            case 'g':          /* Generate New Terrain */
                if(Startup)
                {
                    errflg = 1;
                }
                else
                {
                    Startup = -1;
                }
                break;

            case 's':          /* Scenario <name> */
                if(Startup)
                    errflg++;
                else
                {
                    c = atoi(optarg);
                    if(!c)
                    {
                        if(MatchArg(optarg, "Dullsville"))
                        {
                            c = 1;
                        }
                        else if(MatchArg(optarg, "San_Francisco"))
                        {
                            c = 2;
                        }
                        else if(MatchArg(optarg, "Hamburg"))
                        {
                            c = 3;
                        }
                        else if(MatchArg(optarg, "Bern"))
                        {
                            c = 4;
                        }
                        else if(MatchArg(optarg, "Tokyo"))
                        {
                            c = 5;
                        }
                        else if(MatchArg(optarg, "Detroit"))
                        {
                            c = 6;
                        }
                        else if(MatchArg(optarg, "Boston"))
                        {
                            c = 7;
                        }
                        else if(MatchArg(optarg, "Rio_de_Janeiro"))
                        {
                            c = 8;
                        }
                    }
                    if((c < 1) || (c > 8))
                    {
                        errflg = 1;
                    }
                    else
                    {
                        Startup = c;
                    }
                }
                break;

            case 'd':          /* Display <name> */
            {
                char *d = Displays;

                if(d == NULL)
                {
                    Displays = malloc(strlen(optarg) + 3);
                    sprintf(Displays, "{%s}", optarg);

                    if(strchr(optarg, ':') != NULL)
                    {
                        FirstDisplay = malloc(strlen(optarg) + 1);
                        strcpy(FirstDisplay, optarg);
                    }
                    else
                    {
                        FirstDisplay = malloc(strlen(optarg) + 3);
                        sprintf(FirstDisplay, "%s:0", optarg);
                    }
                }
                else
                {
                    /*
                     * Implicitly set multi player mode if multiple displays given. 
                     */
                    MultiPlayerMode = 1;
                    Displays = malloc(strlen(Displays) + strlen(optarg) + 4);
                    sprintf(Displays, "%s {%s}", d, optarg);
                    free(d);
                }
            }
                break;

            case '?':
                errflg++;
                break;
        }
    }

    if(!errflg && !tkMustExit)
    {
        if((Startup == -1) || (Startup == -2))
        {
            /*
             * Generate New City 
             */
            if((optind != argc) && (optind != argc - 1))
            {
                errflg = 1;
            }
            else
            {
                if(optind == argc - 1)
                    StartupName = argv[optind];
            }
        }
        else if(Startup > 0)
        {
            /*
             * Scenario 
             */
        }
        else if(optind == argc - 1)
        {
            /*
             * Load City 
             */
            Startup = -2;
            StartupName = argv[optind];
        }
        else if(optind == argc)
        {
            /*
             * No arguments 
             */
        }
        else
        {
            errflg = 1;
        }
    }

    if(errflg)
    {
        fprintf(stderr, "usage: %s\n", argv[0]);
        fprintf(stderr, "        [-s(cenario) number|name]\n");
        fprintf(stderr, "        [-g(enerate random map and start playing)\n");
        fprintf(stderr, "        [-l(evel) number|name]\n");
        fprintf(stderr, "        [-w(ire mode: use X11 networking without shared memory)]\n");
        fprintf(stderr, "        [-t(ty mode: interactive TCL session on stdin/stdout)]\n");
        fprintf(stderr, "        [-c(olormap mode: create own X11 colormap on 8 bit screens)]\n");
        fprintf(stderr, "        [-S(ugar mode: enable OLPC Sugar user interface integration)]\n");
        fprintf(stderr, "        [-m(ulti player mode: enable adding multiple players via X11)]\n");
        fprintf(stderr, "        [NewCityName]\n");
        fprintf(stderr, "        [SavedFileName.city]\n");
        fprintf(stderr, "The game level and NewCityName argument are optional, and only apply when\n");
        fprintf(stderr, "starting a new city or generating new terrain.\n");
        fprintf(stderr, "Game levels include: 1: Easy, 2: Medium, 3: Hard\n");
        fprintf(stderr, "Scenarios include: 1: Dullsville, 2: San_Francisco, 3: Hamburg, 4: Bern,\n");
        fprintf(stderr, "		    5: Tokyo, 6: Detroit, 7: Boston, 8: Rio_de_Janeiro\n");
        fflush(stderr);
        sim_exit(0);            // Just sets tkMustExit and ExitReturn
    }

    if((!tkMustExit) && (Displays == NULL))
    {
        char *d = getenv("DISPLAY");

        if(d == NULL)
            d = ":0";

        Displays = malloc(strlen(d) + 3);
        sprintf(Displays, "{%s}", d);
        if(strchr(d, ':') != NULL)
        {
            FirstDisplay = malloc(strlen(d) + 1);
            strcpy(FirstDisplay, d);
        }
        else
        {
            FirstDisplay = malloc(strlen(d) + 3);
            sprintf(FirstDisplay, "%s:0", d);
        }
    }

    if(!tkMustExit)
    {
        env_init();
    }

    if(!tkMustExit)
    {
        tk_main();
    }

    exit(ExitReturn);
}
